//@author A0083338B

import java.util.*;

public class OperationHistory {

	private Stack<Operation> _undoList;
	private Stack<Operation> _redoList;
	private Account _account;
	private BudgetPlanner _bp;
 
	public OperationHistory(Account account){
		_undoList = new Stack<Operation>();
		_redoList = new Stack<Operation>();
		this._account = account;
		this._bp = account.getBudgetPlanner();
	}
	public void add(Operation t) {
		_undoList.push(t);
		_redoList.clear();
	}
	private Operation Undo() {
		if(!_undoList.isEmpty()) {
			Operation i = _undoList.pop();
			_redoList.push(i);
			return i;
		}
		return null;
	}
	
	private Operation Redo() {
		if(!_redoList.isEmpty()){
			   Operation i = _redoList.pop();
			   _undoList.push(i);
			   return i;
		}
		return null;
	}

	public boolean undo() {
		int check = 0;
		String str = null;
		while(check  < 2) {
			Operation instruction = Undo();
			if(instruction == null) return false;
			String cmd = instruction.getCmd();
			if(!instruction.isCategory()) {
				int id = -1;
				if(!instruction.isUpdate() && cmd.equals("add")) {
					id = ((Transaction)instruction.getOperation()).getID();
					if(!(instruction.getOperation() instanceof BudgetPlannerItem)) {
						this._account.deleteTransaction(id);
						this._account.maintainOrder();
					}else this._bp.deleteItem(id);
				}
				if(!instruction.isUpdate() && cmd.equals("delete")) {
					if(!(instruction.getOperation() instanceof BudgetPlannerItem)) {
						this._account.addTransaction(((Transaction)instruction.getOperation()).getID(),(Transaction)instruction.getOperation());
						this._account.maintainOrder();
					}else this._bp.addItem((BudgetPlannerItem)instruction.getOperation());
				}
				if(instruction.isUpdate()) {
					if(check == 0) {
						check++;
						continue;
					}
					if(check == 1) {
						if(!(instruction.getOperation() instanceof BudgetPlannerItem)) {
							this._account.updateTransaction(Integer.parseInt(cmd), (Transaction)instruction.getOperation());
							this._account.maintainOrder();
						}
						else	this._bp.updateItem(Integer.parseInt(cmd), (BudgetPlannerItem)instruction.getOperation());
						check++;
					}
				}
				check = 2;
			}
			else {
				if(cmd.equals("add -c")) {
					String temp = null;
					if(instruction.getOperation() instanceof String) temp = ((String)instruction.getOperation());
					this._account.deleteCategory(temp);
				}
				else if(cmd.equals("delete -c")) {
					String cat = null;
					if(instruction.getOperation() instanceof String) cat = ((String)(instruction.getOperation())).toUpperCase();
					List<Transaction> list = this._account.getDeletedCategories().get(cat + "||" + Account.DEFAULT_CATEGORY);
					this._account.updateCategoriesList(cat, Account.DEFAULT_CATEGORY, list);
				}
				else if(instruction.isUpdate() && cmd.equals("-c")) {
					if(check == 0) {
						str = ((String) instruction.getOperation()).toUpperCase();
						check++;
						continue;
					}
					if(check == 1) {
						if(instruction.getOperation() instanceof String) {
							String str2 = ((String) instruction.getOperation()).toUpperCase();
							List<Transaction> list = this._account.getDeletedCategories().get(str2 + "||" + str);
							this._account.updateCategoriesList(str2, str, list);
						}
						check++;
					}
				}
				else if(cmd.equals("add -m")) {
					String temp = null;
					if(instruction.getOperation() instanceof String) temp = ((String)instruction.getOperation());
					this._account.deletePaymentMethod(temp);
				}
				else if(cmd.equals("delete -m")) {
					String cat = null;
					if(instruction.getOperation() instanceof String) cat = ((String)(instruction.getOperation())).toUpperCase();
					List<Transaction> list = this._account.getDeletedPaymentMethod().get(cat + "||" + Account.DEFAULT_PAYMENT_METHOD);
					this._account.updatePaymentMethodList(cat, Account.DEFAULT_PAYMENT_METHOD, list);
				}
				else if(instruction.isUpdate() && cmd.equals("-m")) {
					if(check == 0) {
						str = ((String) instruction.getOperation()).toUpperCase();
						check++;
						continue;
					}
					if(check == 1) {
						if(instruction.getOperation() instanceof String) {
							String str2 = ((String) instruction.getOperation()).toUpperCase();
							List<Transaction> list = this._account.getDeletedPaymentMethod().get(str2 + "||" + str);
							this._account.updatePaymentMethodList(str2, str, list);
						check++;
						}
					}
				}
				check = 2;
			}
		}
		return true;
	}
	
	public boolean redo() {
		int check = 0;
		String str = null;
		while(check  < 2) {
			Operation instruction = Redo();
			if(instruction == null) return false;
			String cmd = instruction.getCmd();
			if(!instruction.isCategory()) {
				int id = -1;
				if(!instruction.isUpdate() && cmd.equals("delete")) {
					id = ((Transaction)instruction.getOperation()).getID();
					if(!(instruction.getOperation() instanceof BudgetPlannerItem)) {
						this._account.deleteTransaction(id);
						this._account.maintainOrder();
					}else this._bp.deleteItem(id);
				}
				if(!instruction.isUpdate() && cmd.equals("add")) {
					if(!(instruction.getOperation() instanceof BudgetPlannerItem)) {
						this._account.addTransaction(((Transaction)instruction.getOperation()).getID(),(Transaction)instruction.getOperation());
						this._account.maintainOrder();
					}
					else this._bp.addItem((BudgetPlannerItem)instruction.getOperation());
				}
				if(instruction.isUpdate()) {
					if(check == 0) {
						check++;
						continue;
					}
					if(check == 1) {
						if(!(instruction.getOperation() instanceof BudgetPlannerItem)) {
							this._account.updateTransaction(Integer.parseInt(cmd), (Transaction)instruction.getOperation());
							this._account.maintainOrder();
						}
						else	this._bp.updateItem(Integer.parseInt(cmd), (BudgetPlannerItem)instruction.getOperation());
						check++;
					}
				}
				check = 2;
			}
			else {
				if(cmd.equals("delete -c")) {
					String cat = null;
					if(instruction.getOperation() instanceof String) cat = ((String)instruction.getOperation());
					this._account.deleteCategory(cat);
				}
				else if(cmd.equals("add -c")) {
					String cat = null;
					if(instruction.getOperation() instanceof String) cat = ((String)(instruction.getOperation())).toUpperCase();
					this._account.addCategory(cat);
					List<Transaction> list = this._account.getDeletedCategories().get(cat + "||" + Account.DEFAULT_CATEGORY);
					this._account.updateCategoriesList(cat, Account.DEFAULT_CATEGORY, list);
				}
				else if(instruction.isUpdate() && cmd.equals("-c")) {
					if(check == 0) {
						str = ((String) instruction.getOperation()).toUpperCase();
						check++;
						continue;
					}
					if(check == 1) {
						if(instruction.getOperation() instanceof String) {
							String str2 = ((String) instruction.getOperation()).toUpperCase();
							List<Transaction> list = this._account.getDeletedCategories().get(str + "||" + str2);
							this._account.updateCategoriesList(str2, str, list);
						}
						check++;
					}
				}
				else if(cmd.equals("delete -m")) {
					String id = null;
					if(instruction.getOperation() instanceof String) id = ((String)instruction.getOperation());
					this._account.deletePaymentMethod(id);
				}
				else if(cmd.equals("add -m")) {
					String cat = null;
					if(instruction.getOperation() instanceof String) cat = ((String)(instruction.getOperation())).toUpperCase();
					this._account.addPaymentMethod(cat);
					List<Transaction> list = this._account.getDeletedPaymentMethod().get(cat + "||" + Account.DEFAULT_PAYMENT_METHOD);
					this._account.updatePaymentMethodList(cat, Account.DEFAULT_PAYMENT_METHOD, list);
				}
				else if(instruction.isUpdate() && cmd.equals("-m")) {
					if(check == 0) {
						str = ((String) instruction.getOperation()).toUpperCase();
						check++;
						continue;
					}
					if(check == 1) {
						if(instruction.getOperation() instanceof String) {
							String str2 = ((String) instruction.getOperation()).toUpperCase();
							List<Transaction> list = this._account.getDeletedPaymentMethod().get(str + "||" + str2);
							this._account.updatePaymentMethodList(str2, str, list);
						}
						check++;
					}
				}
				check = 2;
			}
		}
		return true;
	}
}
